﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.IO;
using Tsanie.DmPoster.Models;
using System.Xml;
using System.IO.Compression;

namespace Tsanie.DmPoster.Utils {
    public class Net {
        private Form _owner;
        public Net(Form owner) {
            this._owner = owner;
        }

        private void RunAction(string message, Action<string> action) {
            if (action != null) {
                _owner.Invoke(new MethodInvoker(() => {
                    action(message);
                    Application.DoEvents();
                }));
            }
        }
        public bool AvToVid(string av, Action<string> result, Action<string> msgHandler) {
            if (av == null || !av.StartsWith("av")) {
                RunAction("请输入正确的av序号（包含av）！", (msg) => {
                    MessageBox.Show(this._owner, msg, "AV",
                        MessageBoxButtons.OK, MessageBoxIcon.Warning);
                });
                return false;
            }
            string[] avs = av.Substring(2).Split(',');
            string url = Config.m_HttpBase + "/plus/view.php?aid=" + avs[0];
            RunAction("正在连接到" + av, msgHandler);
            if (avs.Length > 1) {
                url += "&pageno=" + avs[1];
            }
            Http.BeginConnect(url, (dl) => {
                dl.Referer = Config.m_HttpBase + "/";
                dl.Headers["Cookie"] = Config.m_Cookie;
            }, (res, dl) => {
                using (Stream response = dl.GetResponse().GetResponseStream()) {
                    RunAction("正在通过" + av + "获取Vid...", msgHandler);
                    StreamReader reader = new StreamReader(response, Encoding.UTF8);
                    string line = null;
                    while ((line = reader.ReadLine()) != null) {
                        int index = line.IndexOf("flashvars=\"");
                        if (index >= 0) {
                            string vars = line.Substring(index + 11);
                            vars = vars.Substring(0, vars.IndexOf("\""));
                            foreach (string v in vars.Split('&')) {
                                index = v.IndexOf("id=");
                                if (index >= 0) {
                                    RunAction("已获得Vid。", msgHandler);
                                    // 执行委托
                                    result(v.Substring(index + 3));
                                    break;
                                }
                            }
                            break;
                        }
                    }
                    reader.Close();
                    reader.Dispose();
                }
            }, (ex) => {
                RunAction(ex.Message, msgHandler);
                RunAction("获取Vid时出现错误！\n" + ex.Message, (msg) => {
                    MessageBox.Show(this._owner, msg, "错误",
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                });
            });
            return true;
        }
        public bool Upload(string av, float offset,
            IEnumerable<BiliComment> comments, Action<string> msgHandler) {
            if (av.ToLower().StartsWith("av")) {
                AvToVid(av, (result) => {
                    UploadDm(result, offset, comments, msgHandler);
                }, msgHandler);
            } else {
                UploadDm(av, offset, comments, msgHandler);
            }
            return true;
        }
        private void UploadDm(string vid, float offset,
            IEnumerable<BiliComment> comments, Action<string> msgHandler) {
            string url = Config.m_HttpBase + "/dm," + vid + "?r=" + Utility.Rnd.Next(1000);
            RunAction("正在查询弹幕服务器id...", msgHandler);
            Http.BeginConnect(url, (up) => {
                up.Timeout = 10000;
                up.Referer = Config.m_HttpBase + "/PADplayer.swf";
                up.Accept = "text/xml";
                up.Headers["Cookie"] = Config.m_Cookie;
                up.Headers["Accept-Encoding"] = "gzip";
            }, (result, up) => {
                using (Stream stream = up.GetResponse().GetResponseStream()) {
                    XmlReader reader = XmlReader.Create(new DeflateStream(stream,
                        CompressionMode.Decompress));
                    string dm_inid = null;
                    while (reader.Read()) {
                        if (reader.Name == "chatid" && (reader.NodeType ==
                            XmlNodeType.Element)) {
                            dm_inid = reader.ReadString();
                            break;
                        }
                    }
                    reader.Close();
                    UploadDmExec(dm_inid, offset, comments, msgHandler);
                }
            }, (ex) => {
                RunAction(ex.Message, msgHandler);
                RunAction("获取弹幕服务id时出现错误！\n" + ex.Message, (msg) => {
                    MessageBox.Show(this._owner, msg, "错误",
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                });
            });
        }
        private void UploadDmExec(string dm_inid, float offset,
            IEnumerable<BiliComment> comments, Action<string> msgHandler) {
            string url = Config.m_HttpBase + "/member/dmm.php";
            RunAction("正在上传弹幕...", msgHandler);
            Http.BeginConnect(url, (post) => {
                post.Method = "POST";
                post.Referer = Config.m_HttpBase + "/member/dmm.php";
                post.Headers["Origin"] = Config.m_HttpBase;
                post.ContentType = "application/x-www-form-urlencoded";
                post.Headers["Cookie"] = Config.m_Cookie;

                string memo = "mode=asspost&dm_inid=" + dm_inid;
                memo += StringUtil.UrlEncode(
                    BiliComment.SubtitlesToString(comments, offset));
                byte[] bs = Encoding.ASCII.GetBytes(memo);
                post.ContentLength = bs.Length;
                using (Stream write = post.GetRequestStream()) {
                    write.Write(bs, 0, bs.Length);
                    write.Flush();
                    write.Close();
                }
            }, (res, post) => {
                using (Stream stream = post.GetResponse().GetResponseStream()) {
                    StreamReader reader = new StreamReader(stream, Encoding.UTF8);
                    string str = null;
                    while ((str = reader.ReadLine()) != null) {
                        if (str.StartsWith("document.write(\"") && str[16] != '<') {
                            string msg = str.Substring(16, str.IndexOf('\"', 16) - 16);
                            RunAction(msg, msgHandler);
                            RunAction(msg, (m) => {
                                MessageBox.Show(this._owner, m, "上传xml");
                            });
                            break;
                        }
                    }
                    reader.Close();
                    reader.Dispose();
                }
            }, (ex) => {
                RunAction(ex.Message, msgHandler);
                RunAction("上传弹幕时出现错误！\n" + ex.Message, (msg) => {
                    MessageBox.Show(this._owner, msg, "错误",
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                });
            });
        }
        public bool Download(string av, Action<string> msgHandler, Action<Stream> exec) {
            if (av.ToLower().StartsWith("av")) {
                AvToVid(av, (result) => {
                    DownloadExec(result, msgHandler, exec);
                }, msgHandler);
            } else {
                DownloadExec(av, msgHandler, exec);
            }
            return true;
        }
        private void DownloadExec(string vid, Action<string> msgHandler,
            Action<Stream> exec) {
            RunAction("正在连接弹幕服务器...", msgHandler);
            string url = Config.m_HttpBase + "/dm," + vid + "?r=" + Utility.Rnd.Next(1000);
            Http.BeginConnect(url, (dl) => {
                dl.Timeout = 10000;
                dl.Referer = Config.m_HttpBase + "/PADplayer.swf";
                dl.Accept = "text/xml";
                dl.Headers["Cookie"] = Config.m_Cookie;
                dl.Headers["Accept-Encoding"] = "gzip";
            }, (result, dl) => {
                if (exec != null) {
                    using (Stream stream = dl.GetResponse().GetResponseStream()) {
                        _owner.Invoke(new MethodInvoker(() => {
                            exec(stream);
                        }));
                    }
                }
            }, (ex) => {
                RunAction(ex.Message, msgHandler);
                RunAction("下载弹幕时出现错误！\n" + ex.Message, (msg) => {
                    MessageBox.Show(this._owner, msg, "错误",
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                });
            });
        }
        public bool CheckCookie(string cookie, Action<string> msg, Action<Level> exec,
            Action<Exception> err) {
            Http.BeginConnect(Config.m_HttpBase + "/dad.php", (request) => {
                request.Timeout = 5000;
                request.Referer = Config.m_HttpBase + "/";
                request.Headers["Cookie"] = cookie;
            }, (result, request) => {
                if (exec != null) {
                    using (Stream stream = request.GetResponse().GetResponseStream()) {
                        StreamReader reader = new StreamReader(stream, Encoding.UTF8);
                        string line;
                        bool login = false;
                        while ((line = reader.ReadLine()) != null) {
                            if (line.StartsWith("<level>")) {
                                line = line.Substring(7, line.IndexOf('<', 7) - 7);
                                _owner.Invoke(new MethodInvoker(() => {
                                    exec(StringUtil.LevelFromString(line));
                                }));
                                login = true;
                            }
                        }
                        reader.Close();
                        reader.Dispose();
                        if (!login) {
                            _owner.Invoke(new MethodInvoker(() => {
                                exec(Level.Guest);
                            }));
                        }
                    }
                }
            }, (ex) => {
                if (err != null) {
                    _owner.Invoke(new MethodInvoker(() => {
                        err(ex);
                    }));
                }
            });
            return true;
        }
    }
}
